﻿using ServiceStack.DataAnnotations;
using STHPMS1.BLL.B_Core;
using STHPMS1.Common.C_Entity.Stmpms1;
using STHPMS1.ICore;
using STHPMS1.ICore.I_BLL.Bus;
using STHPMS1.ICore.I_Entity.Info;
using STHPMS1.ICore.I_Entity.Stmpms1;
using STHPMS1.ICore.I_Serv;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using STHPMS1.Common.C_Extension;
using System.Linq;
using STHPMS1.Common.C_Enum;
using STHPMS1.ICore.I_DAL;
using System.Text;


namespace STHPMS1.BLL.B_Bus
{
    public class Dm_TrafaxleBus : BllBase, IDm_TrafaxleBill
    {
        public void Save<T>(T entity)
            where T : class ,IDm_Trafaxle
        {
            if (this.Scene.Dal.Sthpms1.Update(entity) == 0)
            {
                this.Scene.Dal.Sthpms1.Insert(entity);
            }
        }

        public void Remove(IDm_Trafaxle entity)
        {
            this.Scene.Dal.Sthpms1.Delete(entity);
        }

        public IEnumerable<T> Get<T>(Expression<Func<T, bool>> predicate, IPagingInfo info)
            where T : class, IDm_Trafaxle
        {
            return this.Scene.Dal.Sthpms1.Select<T>(predicate, info);
        }

        public void GenerateAxleLoadAndAge()
        {
            ISthpms1Dao dao = this.Scene.Dal.Sthpms1;

            var carList = dao.Select<Dm_Default_Asp>();
            var ratingList = dao.Select<Dm_Default_Rating>();
            var serv = MyApp.Locator.GetInstance<IDeflectionCalculateService>();
            serv.CalacDeflection(dao);

            List<S_Apply> applist = dao.Select<S_Apply>();
            List<Dm_Esalage> esalList = new List<Dm_Esalage>();
            List<B_Invntory> invList = new List<B_Invntory>();

            foreach (var apply in applist)
            {
                CalacAxleLoadAndAgeInApply(dao, carList, ratingList, apply, serv, esalList, invList);
            }

            StringBuilder sb = new StringBuilder();
            foreach (var item in invList.GroupBy(k => k.Rdwayid))
            {
                B_Roadway road = dao.SingleById<B_Roadway>(item.Key);
                if (road == null) throw new Exception("没有找到路线信息-" + item.Key);

                var invRdwayids = item.ToList().OrderBy(k => k.Beginmp);
                double beginmp = road.Beginmp;

                foreach (var invItem in invRdwayids)
                {
                    if (invItem.Beginmp == beginmp)
                    {
                        beginmp = invItem.Endmp;
                    }
                    else if (invItem.Beginmp < beginmp)
                    {
                        continue;
                    }
                    else
                    {
                        sb.AppendFormat("路线：{0} 桩号<{1}-{2}>之间的交通量不存在! \r\n", road.Rdwayid, beginmp.PrintStake(), invItem.Beginmp.PrintStake());
                    }
                }

                if (beginmp != road.Endmp)
                {
                    sb.AppendFormat("路线：{0} 桩号{1}-{2}之间的交通量不存在! \r\n", road.Rdwayid, beginmp.PrintStake(), road.Endmp.PrintStake());

                }            
            }
            
            if (esalList.Count > 0)
            {
                dao.SaveAll(esalList);
            }

            if (sb.Length > 0)
                throw new Exception(sb.ToString());

        }

        /// <summary>
        /// 计算累计当量轴载与路龄的关系
        /// </summary>
        /// <param name="applist"></param>
        public void CalacAxleLoadAndAge(List<IS_Apply> applist)
        {
            ISthpms1Dao dao=this.Scene.Dal.Sthpms1;

            var carList = dao.Select<Dm_Default_Asp>();
            var ratingList = dao.Select<Dm_Default_Rating>();
            var serv = MyApp.Locator.GetInstance<IDeflectionCalculateService>();
            serv.CalacDeflection(dao);

            List<Dm_Esalage> esalList = new List<Dm_Esalage>();
            List<B_Invntory> invList = new List<B_Invntory>();

            foreach (var apply in applist)
            {
                CalacAxleLoadAndAgeInApply(dao, carList, ratingList, apply, serv, esalList, invList);                
            }

            if (esalList.Count > 0)
            {                
                dao.SaveAll(esalList);
            }            
        }
        /// <summary>
        /// 计算一个应用区间的累计当量轴载与路龄的关系
        /// </summary>
        /// <param name="dao"></param>
        /// <param name="carList"></param>
        /// <param name="ratingList"></param>
        /// <param name="apply"></param>
        private void CalacAxleLoadAndAgeInApply(ISthpms1Dao dao, List<Dm_Default_Asp> carList, List<Dm_Default_Rating> ratingList, IS_Apply apply, IDeflectionCalculateService serv, List<Dm_Esalage> esalList, List<B_Invntory> invList)
        {
            var invntoryList = dao.Select<B_Invntory>(p => p.Rdwayid == apply.Apprdid &&
                                                (p.Beginmp >= apply.Appbeginmp && p.Endmp <= apply.Appendmp) &&
                                                p.Direction_Dictid == apply.Direction_Dictid);


            foreach (var invntory in invntoryList)
            {
                if (invntory.Pvmttype_Dictid != PavementTypeEnum.P21.GetEnumValue()) continue;//现在只计算沥青路面
                CalacAxleLoadAndAgeInSeg(dao, carList, ratingList, apply, serv, invntory, esalList);
                invList.Add(invntory);
            }

        }

        /// <summary>
        /// 计算一个基础路段
        /// </summary>
        /// <param name="dao"></param>
        /// <param name="carList"></param>
        /// <param name="ratingList"></param>
        /// <param name="apply"></param>
        /// <param name="serv"></param>
        /// <param name="invntory"></param>
        private void CalacAxleLoadAndAgeInSeg(ISthpms1Dao dao, List<Dm_Default_Asp> carList, List<Dm_Default_Rating> ratingList, IS_Apply apply, IDeflectionCalculateService serv, B_Invntory invntory,List<Dm_Esalage> esalList)
        {

            Dm_Default_Asp car = carList.FirstOrDefault<Dm_Default_Asp>(p => p.Lanes == invntory.Numlanes);
            if (car == null) throw new Exception("车道系数默认值没有找到！-"+invntory.Name);
            Dm_Default_Rating rating = ratingList.FirstOrDefault<Dm_Default_Rating>(p => p.Rdclass_Dictid == invntory.Rdclass_Dictid);
            if (rating == null) throw new Exception("设计年限,增长率默认值没有找到！-"+invntory.Name);
            if (rating.Year_Asp == null) throw new Exception("设计年限数据为空-" + invntory.Name);

            IEnumerable<IS_Trfvolsurvey> trfList = dao.Select<S_Trfvolsurvey>(p => p.Applyid == apply.Applyid, null, k => k.Importdate, false);
            S_Axleload axle = dao.Single<S_Axleload>(p => p.Applyid == apply.Applyid);
            if(trfList.Count()==0)    return ;


            List<AxeloadEasl> dict = new List<AxeloadEasl>();
            foreach (var trf in trfList)
            {
                double d =serv.CalcDailyEASL(trf, axle);
                int a=trf.Importdate.Value.Year-invntory.Begindate.Value.Year;

                AxeloadEasl axeload = dict.FirstOrDefault(p => p.Age == a);
                if (axeload!=null)
                {
                    axeload.Deflection = (axeload.Deflection + d) / 2;  
                }else{
                    dict.Add(new AxeloadEasl() { Age = a, Deflection = d });
                }
            }

            dict.Sort(new Comparison<AxeloadEasl>((a,b)=>a.Age-b.Age));

            double growth = rating.Growth_Rate.ToD();
            int maxAge = dict[dict.Count - 1].Age;
            double esal = 0;
            short age = 0;
            double n = 0;
            double aadt = 0;


            for (; age <= dict[0].Age; age++)
            {
                Dm_Esalage e3 = new Dm_Esalage();
                n=dict[0].Deflection;

                if (age < dict[0].Age)
                {
                    aadt = serv.CalcAADT(n, car.Lanecoef.ToD(), car.Directcoef.ToD());
                    int t = maxAge - age;
                    aadt = aadt / Math.Pow((1 + growth), t);
                }
                else
                {
                    aadt = serv.CalcAADT(n, car.Lanecoef.ToD(), car.Directcoef.ToD());
                }

                e3.Segid = invntory.Segid;
                e3.Perfyear = age;
                e3.Aadt = aadt;
                esal += aadt;
                e3.Easl = esal;

                esalList.Add(e3);
            }

            int index = 0;
            if (age != maxAge)
            {
                for (; age <= maxAge; age++)
                {
                    AxeloadEasl minEasl = dict[index];
                    AxeloadEasl maxEasl = dict[index + 1];


                    if (age == dict[index].Age)
                    {
                        n = dict[index].Deflection;
                        index++;
                        if (index > dict.Count - 2) index = dict.Count - 2;
                    }
                    else
                    {
                        n = (maxEasl.Deflection - minEasl.Deflection) / (maxEasl.Age - minEasl.Age );
                    }


                    aadt = serv.CalcAADT(n, car.Lanecoef.ToD(), car.Directcoef.ToD());
                    Dm_Esalage e1 = new Dm_Esalage();
                    e1.Segid = invntory.Segid;
                    e1.Perfyear = age;
                    e1.Aadt = aadt;
                    esal += e1.Aadt.ToD();
                    e1.Easl = esal;

                    esalList.Add(e1);
                }
            }

            int degsinYear = age + (int)rating.Year_Aspmax;
            for (; age < degsinYear; age++)
            {
                aadt = serv.CalcAADT(n, car.Lanecoef.ToD(), car.Directcoef.ToD());
                int t = age-maxAge;
                aadt = aadt * Math.Pow((1 + growth), t);

                Dm_Esalage e1 = new Dm_Esalage();
                e1.Segid = invntory.Segid;
                e1.Perfyear = age;
                e1.Aadt = aadt;
                esal += aadt;
                e1.Easl = esal;

                //e1.Easl = esal + serv.CalcDesginerEASL(aadt, degsinYear, rating.Growth_Rate.ToD());

                esalList.Add(e1);
            }
        }
    }

    class AxeloadEasl
    {
        public int Age;
        public double Deflection;
    }
}


